﻿using IdentityModel.Client;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.Owin;
using Microsoft.Owin.Extensions;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;

[assembly: OwinStartup("WebFormStartup", typeof(WebForms.Startup))]

namespace WebForms
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions()
            {
                AuthenticationType = "Cookies",
                //LoginPath = new PathString("/Account/Login.aspx"),
                //AuthenticationType = "Jwt",
                //CookieName = "idsrv2",
                ExpireTimeSpan = TimeSpan.FromDays(1), //设置Cookie的过期时间
                SlidingExpiration = true,
            });

            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = "oidc",
                SignInAsAuthenticationType = "Cookies",
                Authority = "https://localhost:5001/",
                ClientId = "webforms",
                ClientSecret = "secret",
                RedirectUri = "https://localhost:44379/Account/Callback",
                PostLogoutRedirectUri = "https://localhost:44379",
                //RequireHttpsMetadata = false,
                ResponseType = "id_token token",
                Scope = "openid profile api1",
                UseTokenLifetime = false,

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    SecurityTokenValidated = async n =>
                    {
                        var claims_to_exclude = new[]
                        {
                                    "aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash"
                            };

                        var claims_to_keep =
                            n.AuthenticationTicket.Identity.Claims
                            .Where(x => false == claims_to_exclude.Contains(x.Type)).ToList();
                        claims_to_keep.Add(new Claim("id_token", n.ProtocolMessage.IdToken));

                        if (n.ProtocolMessage.AccessToken != null)
                        {
                            claims_to_keep.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));

                            var client = new HttpClient();
                            client.BaseAddress = new Uri("https://localhost:5001/core/connect/userinfo");
                            client.SetBearerToken(n.ProtocolMessage.AccessToken);
                            var userRq = new UserInfoRequest();
                            userRq.Token = n.ProtocolMessage.AccessToken;

                            var userInfoResponse = await client.GetUserInfoAsync(userRq);

                            //var userInfoClient = new UserInfoClient(new Uri("https://localhost:5001/core/connect/userinfo"), n.ProtocolMessage.AccessToken);
                            //var userInfoResponse = await userInfoClient.GetAsync();
                            var userInfoClaims = userInfoResponse.Claims
                            .Where(x => x.Type != "sub") // filter sub since we're already getting it from id_token
                            .Select(x => new Claim(x.Type, x.Value));
                            claims_to_keep.AddRange(userInfoClaims);
                        }

                        var ci = new ClaimsIdentity(
                            n.AuthenticationTicket.Identity.AuthenticationType,
                            "name", "role");
                        ci.AddClaims(claims_to_keep);

                        n.AuthenticationTicket = new Microsoft.Owin.Security.AuthenticationTicket(
                            ci, n.AuthenticationTicket.Properties
                        );
                    },
                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                        {
                            var id_token = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
                            n.ProtocolMessage.IdTokenHint = id_token;
                        }

                        return Task.FromResult(0);
                    }
                }
            });
            app.UseStageMarker(PipelineStage.Authenticate);
        }

    }
}
